5. The Entity Alias Models

(Thanks to Brian Martin who clarified most of this section)

Alias models can be used for entities, like players, objects, or monsters. Some entities can use sprite models (that are similar in appearance to those of DOOM, though the structure is totally different) or even maybe models similar to those of the levels.

Importing models from 3DS or the likes is now quite easy. You'll just have to work out a few things on your own (like calculation of the vertex normals, matching them with the vertex normal table, finding the bounding area of the object, and scaling the vertices to 8-bit values).

5.1 Presentation of Alias Models

You need not bother too much about the way Alias Models are rendered, just keep in mind that the more simple the model, the faster the game will be.

Here is an attempt at describing what the different parts of the model represent. This description is a bit outdated, though.

First imagine a wireframe model of the entity, made of triangles. This gives the general shape of the entity. For instance, imagine you have the general shape of a cow, made of triangles in 3D space.

The 3D vertices define the position of triangles, and contrary to level models, there is no need for elaborate stuff like nodes, planes, faces. Only triangles and vertices.

Now, there is something missing: the skin. A cow without skin looks pretty ugly.

Imagine that you have a flat carpet made of the skin of an unlucky cow. All you need to do is put some parts of this carpet at the relevant place on the wireframe model of the cow, and you'll get a fairly realistic (though a bit polygonal) cow. Actually, you will need two carpets: one for the upper part and one for the lower part.

For each triangle in the wireframe model of the cow, there will be a corresponding triangle cut from the skin picture. Or, in other words, for each 3D vertex of a triangle, there will be a corresponding 2D vertex positioned on the skin picture.

It is not necessary that the triangle in 3D space and the triangle on the skin have exactly the same shape (in fact, it is not possible for all triangles) but they should have shapes roughly similar, to limit distortion and aliasing.

By the way: there is no Mip mapping on the Alias models, so they don't look very good in distance, which is not too bad since they are constantly supposed to be moving or changing. If you want then to look fine, do them with BSP models. But then they won't move.

5.2 Animating Alias models

The Alias Model animation is based on frames (in DOOM, sprites were also animated by frames). So the deformations are defined once and for all, and there is no skeletal model or any similar physical model involved in the deformations... well, at least not in real time.

Once the general shape of the model (for instance, a cow) is defined, and the skin is mapped correctly on that shape, animation is pretty straightforward: just move the triangles around and it will seem to move.

To move the triangle, you need only modify the position of the 3D vertices that are part of it. For instance, to move the leg of the cow, you will move the vertices that define the endpoints of the legs. You will also move the other vertices a bit, so that the movement looks less mechanical.

Chances are that creating a fine looking animation is gonna be a very tough job, a bit like with the DOOM sprites. I would bet that the quality of the animation will be the most critical point.

Note that the animation consists only in changing vertex positions (and that's why there is one set of vertices for each animation frame).

The skin of the cow is not modified, neither are the definition of the triangles. If you want blood stains to appear on the skin, you'll have to hide the original triangle, by reducing it or by putting another triangle in front.

As remarked by Bernd Kreimeier, this method is similar to the trick squids use when they want to change color: their skin is made os small areas, of two different colors, and they can reduce or enlage them at will.

Along the same idea, if you want parts of the models, like head, weapons and the like, to go flying away when they are cut, then they must be defined using parts of the skin that are separate from the parts used for the body.

Or you can use separate models, like the player gibs, but then the original part must be reduced to a very small size.

5.3 Alias Model .MDL file format

The .MDL files are collection of lumps, but contrary to .BSP files there are no pointers to access the lumps directly, and it is suspected that there will be, in future versions of the models.

Once you have the file header, you can find all the other parts, just by calculating their position in the file.

A Model file contains:

  1. A skin texture, that describes the color of the skin and clothes of the creature, or whatever it can be wearing.
  2. A list of skin vertices, that are just the position of vertices on the skin texture.
  3. A list of triangles, the describe the general shape of the model.
  4. A list of animation frames.
    Each frame holds a list of the 3D vertices and the index of the precalculated vertex normal.

5.3.0 Alias Model Header

Here is the format of the .MDL file header:

typedef struct
{ long id;                     // 0x4F504449 = "IDPO" for IDPOLYGON
  long version;                // Version = 6
  vec3_t scale;                // Model scale factors.
  vec3_t origin;               // Model origin.
  scalar_t radius;             // Model bounding radius.
  vec3_t offsets;              // Eye position (useless?)
  long numskins ;              // the number of skin textures
  long skinwidth;              // Width of skin texture
                               //           must be multiple of 8
  long skinheight;             // Height of skin texture
                               //           must be multiple of 8
  long numverts;               // Number of vertices
  long numtris;                // Number of triangles surfaces
  long numframes;              // Number of frames
  long synctype;               // 0= synchron, 1= random
  long flags;                  // 0 (see Alias models)
  scalar_t size;               // average size of triangles
} mdl_t;

The size of this header is 0x54 bytes (84).

5.3.1 Alias Model Skins

The model skins are flat pictures that represent the texture that should be applied on the model. There can be more than one skin, though usually there is only one.

The structure of model skins

The structure of the skin is similar to the structure of Sprites textures.

You will find the first skin just after the model header, at offset baseskin = 0x54. There are numskins skins to read.

Each of these model skins is either a single picture (type=0) or a group of pictures (type!=0).

If the skin is made of a single picture, the structure is:

typedef struct
{ long   group;                // value = 0
  u_char skin[skinwidth*skinheight]; // the skin picture
} skin_t;

If the skin is made of a group of pictures, the structure is:

typedef struct
{ long group;                  // value = 1
  long nb;                     // number of pictures in group
  float time[nb];              // time values, for each picture
  u_char skin[nb][skinwidth*skinheight]; // the pictures 
} skingroup_t;                                                 

The skin pictures

The skin pictures are a table of u_char, which represent an index in a color table. It is suspected that index 0xFF is not a color, but an indication of transparency.

The width of skins must be a multiple of 4, to ensure long word alignement.

Those pictures are usually made of at least two pieces: one is used for the front of the model, the other for the back of the model.

Actually, there may be as many pieces as there are independent parts in the model. For instance, for the player, there are two pieces that defines the body, and two others that define the gun.

Note that the back skin of a given model part must be on the same height, but translated width/2, relatively to the front skin part. The back skin part must also be inverted along the vertical axis.

This design is used to allow the correct rendering of a seamless skin texture, using Skin Vertices with onseam == 0x20, on the skin border.

5.3.2 Alias Model Skin Vertices

A .MDL file is made of a list of vertices. To each of these vertices corresponds a 3D position, a normal, and a position on the skin picture, for texture mapping.

The list of skin vertices indicates only the position on texture picture, not the 3D position. That's because for a given vertex, the position on skin is constant, while the position in 3D space varies with the animation.

The list of skin vertices is made of these structures:

typedef struct
{ long onseam;                 // 0 or 0x20
  long s;                      // position, horizontally
                               //  in range [0,skinwidth[
  long t;                      // position, vertically
                               //  in range [0,skinheight[
} stvert_t;

s and t are (X,Y) position on the skin picture.

onseam is a flag, and if non zero it means that the vertex is on the boundary between the skin part that is applied on the front of the model, and the skin part that is applied on the back of the models (i.e. on the edge).

If a vertex is onseam, but is part of a triangle that is on the back side of the model (facesfront is 0), then skinwidth/2 must be added to s so as to find the actual value of s.

The skin vertices are stored in a list, that is stored at offset offset baseverts = baseskin + skinsizes:

stvert_t vertices[numverts];

skinsizes is the sum of the size of all skin pictures.

5.3.3 Alias Model Triangles

An Alias Model is made of a set of triangle facets, with vertices at the boundaries. Triangles should all be valid triangles, not degenerates (like points or lines).

Only vertices index are stored in triangles. the normal vector of the surface is reconstituted from the vertex position.

Here is the structure of triangles:

typedef struct
{ long facesfront;             // boolean
  long vertices[3];            // Index of 3 triangle vertices
                               // in range [0,numverts[
} itriangle_t;

Note that the index of a given vertex is the same in the skin vertex table and in the frame table.

At offset basetri = baseverts + numverts * sizeof(stvert_t) in the .MDL file, you will find:

itriangle_t triangles[numtris];

The boolean facesfront indicates if the triangle is part of the front or the back skin. 1 means that it is on the front skin, 0 means that it is on the back skin.

When the triangle is on the back skin, then any skin vertex that is on the skin seam (as indicated by onseam=1) must have it's s coordinate increased by skinwidth/2.

As a matter of fact, on the skin picture, the back skin is always situtated at the same level as the front skin, but moved by skinwidth/2 to the right (check this, with any model).

The following code might make this easier to understand:

  for(j=0; j < numtris; j++)
  {
    for(i=0; i < 3 ; i++)
    { 
      vertex = triangles[j].vertices[i]
      s = vertices[vertex].s;
      t = vertices[vertex].t;
      if( (vertices[vertex].onseam) && (!triangle[j].facesfront))
      { 
        s += skinwidth / 2;
      }
      /* use s and t as the coordinates of the vertex*/
    }
  }

5.3.4 Alias Model Frames

An Alias Model contains a set of animation frames, which can be used in relation with the behavior of the modeled entity, so as to display it in various postures (walking, attacking, spreading its guts all over the place...).

This frame structure is rather complex to figure out, because:

The frame vertices

Each frame vertex is defined by a 3D position and a normal for each of the vertices in the model.

typedef struct
{ u_char packedposition[3];    // X,Y,Z coordinate, packed on 0-255
  u_char lightnormalindex;     // index of the vertex normal
} trivertx_t;

To get the real X coordinate, from the packed coordinates, multiply the X coordinate by the X scaling factor, and add the X origin. Both the scaling factor and the origin can be found in the Model Header.

The formula for calculating positions is:

vec3_t position[i] = ( scale[i] *  packedposition[i] ) + origin[i]
Where scale, and origin can be found as vectors in the Model Header.

The vertex normals

The lightnormalindex field is an index to the actual vertex normal vector. This vector is the average of the normal vectors of all the faces that contain this vertex.

This information is necessary to calculate the Gouraud shading of the faces, but actually a crude estimation of the actual vertex normal is sufficient. That's why, to save space and to reduce the number of computations needed, it has been chosen to approximate each vertex normal.

The ordinary values of lightnormalindex are comprised between 0 and 161, and directly map into the index of one of the 162 precalculated normal vectors that can be found in Appendix B.

Value 255 is sometimes used in models, but this is a bug. Only values 0 through 161 should be used.

The simple frames

The simple frames can come standalone or in groups (see below). They always have the same structure:

typedef struct
{ trivertx_t min;              // minimum values of X,Y,Z
  trivertx_t max;              // maximum values of X,Y,Z
  char name[16];               // name of frame
  trivertx_t frame[numverts];  // array of vertices
} simpleframe_t;

The size of each simple frame is sizeframe = 0x18 + numverts * trivertx_t;.

The number of vertices is numverts, and to each of the vertex declared here corresponds a Skin Vertex with the same index.

The frame header contains two vertex definitions, min and max, that define a bounding box around the whole frame: all the other vertices must be inside that bounding box.

However, that bounding box is only used for collision detection, so if you make it smaller than it should be the model will still display fine, but you can get very close to it before hitting it.

To get the floating point values corresponding to min and max, treat them as if they were ordinary vertex positions.

The frames

These are the actual animation frames, made of a single frame, or a group of single frames, with timing indication.

The beginning of the frames can be found in the .MDL file, at offset baseframes = basetri + numtris * sizeof(itriangle_t);.

Each frame must be read separately, since they may not have a constant size.

If the frame is made of one simple frame:

                                      
struct               
{ long type;             // Value = 0
  simpleframe_t frame;         // a single frame definition
}

If the frame is made of a group of simple frames:

 
struct
{ long type;                   // Value != 0
  trivertx_t min;              // min position in all simple frames
  trivertx_t max;              // max position in all simple frames
  float time[nb]               // time for each of the single frames
  simpleframe_t frames[nb];    // a group of simple frames
}

5.4 How to create Alias Models

This information from Steve Tietze was obtained on AfterShock, a Web site animated by Joost Schuur.

You can create an Alias model from the Alias .TRI files, using the quake utils released by id software, or from 3DS files, using a modified version of these tools. The exact usage of these tools is beyond the scope of this document. Note that the program Interchange y Senders can convert many file formats to .TRI

5.4.1 Restriction on the geometry

The Alias model you will use as a basis for your Quake model must be a bit specific. You just can't use any 3D model as a basis:

5.4.2 Creating the skin

id software has a program called texmake that will take a model, and create an outline skin (with vertices and lines drawn, to help positioning) as a .LBM file.

If your skin isn't showing up make sure your model scale is in meters.

Beware that you must use the same color palette as the game palette, otherwise the skin will look real strange.

Another option would be to start from an existing skin and position all the skin vertices by hand: see the MDL tool, by Brian Martin.

Note that texmake also indicates you the scale size of the object, an information that's needed.

5.4.2 Defining the frames of the object

The frames should be defined in a Quake C file, that will be processed.

Once you have completed your quake c file its time to run it though model gen. Save the quake c file as armor.qc.

Next step is to make 2 copies of your object. Name your object base.tri and armor.tri The reason for this is that when your run the model gen it will look for base from the $base base file and armor from the first frame of the armor in $frame armor.

Once you have completed make sure that all these files are in one directory:

base.tri
armor.tri 
skin.lbm
armor.qc

Then simply run modelgen armor.qc which will then create a armor.mdl file which quake reads when running the game. If you have done everything right you should now see a armor.mdl file in the same directory.

Now the fun part. Lets replace the your object with the armor icon in the game.

There are a few things you need to know before you do this. In the quake dir create a directory structure like id1.

Here is a break down of what you will need to make maps gfx and models. Create these directories:

  test/
  test/gfx/
  test/progs/
  test/maps/
  test/sound/

Now assuming you have the registered version and did not pirate this version you can go on then. damn you to hell if you didn't buy this.

Copy your armor.mdl file into test/progs/ dir. Then run quake with these command parameters.

quake -game test 
This will bring you into quake and it should replace all the armor icons with your object icon.

THINGS TO KEEP IN MIND:

TROUBLESHOOTING:

If texmake or modelgen doesn't seem to work or hang then there is a problem with your object. There are several reasons for this:

  1. You could have a non-triangle polygon in your object.
  2. You could have repeated points that wernt deleted.
  3. Scale of your object could be wrong. Meters has best output.

That's it for now.. if you have any questions email gateway@rogue-ent.com.
Steve Tietze (Rogue Entertainment)